import java.util.{Date, Calendar};
import java.io.{File, PrintWriter};

class Proceso (parent : Proceso, comando : String, pid : Int) {
  // Crear posibles estados de los procesos
  val NEW = 0;
  val READY = 1;
  val RUNNING = 2;
  val WAITING = 3;
  val TERMINATED = 4;
  
  // Declarar variables y objetos de instancia
  private var estado : Int = NEW; 
  private var hijos : List[Proceso] = List();
  private var programa : String = null;
  private var archivo : String = null;
  val instrucciones : List[String] = List();
  var linea : Int = 0;
  var archivosAbiertos : List[File] = Nil; 
  var resultado : Any = "";
    
  // Mandar información para el logger
  logger ps "Proceso " + pid + " iniciado.\n" +
  	"Ejecuta el programa " + comando + ".";  
  
  /*
  */
  def isSincrono() : Boolean = {
    if(parent == null) archivo == null;
    else parent.isSincrono;
  }
  
  /*
  */
  def configurar() {
     
    // Definir programas del sistema
    //val kill = """\s*kill\s*(\>(\s)?<file>([\w]+?))?\s*""".r
    val kill = """\s*kill\s*.*""".r
    val ls   = """\s*ls\s*.*""".r
    val ps   = """\s*ps\s*.*""".r
    val shutdown = """\s*shutdown\s*""".r
    
    // Revisar si es un proceso sincrono o asíncrono
    val pos : Int = comando.indexOf(">");
    if (pos > -1) {
      programa = comando.substring(0, pos).trim;
      archivo = comando.substring(pos + 1, comando.length).trim;
      debugger ! "Proceso asíncrono. " + programa + " - " + archivo;
    } else {
      programa = comando trim;
      debugger ! "Proceso síncrono. " + programa;
    }
    
    // Revisar si es un proceso con padre
    if(parent != null) {
      parent.hijos = parent.hijos ++ List(this);
    }

    
    // Evaluar si es un programa del sistema (System Program)
     programa match {
      case texto  if(texto.startsWith("debug")) => {
        debugger ! "Programa del sistema: Cambiar el modo del debugger.";
        
        debugger cambiarModo;
        
        this terminar;
      } case texto  if(texto.startsWith("ps")) => {
        debugger ! "Programa del sistema: mostrar procesos activos.";
        
        resultado = sistema.ps()
        
        this terminar;
        
      } case texto if(texto.startsWith("ls")) => {
    	  // Info
    	  debugger ! "Programa del sistema: mostrar archivos.";
    	  
    	  // Declarar variables y objetos
    	  resultado = "";
    	  
    	  // Abrir directorio raíz
          val directorio : File = new File(System getProperty "user.dir");
          val elementos : Array[File] = directorio.listFiles( );
          for (archivo <- directorio listFiles)  {
            if(archivo isFile) resultado += (archivo getName) + "\n";
          }
          
          // Devolver valor calculado
          this terminar;
          resultado;
      } case texto if(texto.trim().startsWith("shutdown")) => {
    	  
    	  // Cerrar el debugger.
    	  debugger ! "Programa del sistema: se sale del sistema operativo.";
       	  debugger ! debugger.cerrar;
		  while(debugger.mailboxSize > 0) {
			  Thread.sleep(200);
		  }
			
		  // Terminar concurrencia.
	      this terminar;
		  resultado = sistema.salir;
      		
      } case texto if(texto.startsWith("kill")) => { 
    	  debugger ! "Programa del sistema: matar un proceso.";
      	  this terminar;
      } case _ => { 
      		      		
		this terminar;
      }

    
      
    /*         
    	archivoDiscotienda = nombreArchivoDiscotienda;
        File archivo = new File( archivoDiscotienda );
        if( archivo.exists( ) )
        {
            // El archivo existe: se debe recuperar de all� el estado del modelo del mundo
            try
            {
                ObjectInputStream ois = new ObjectInputStream( new FileInputStream( archivo ) );
                discos = ( ArrayList )ois.readObject( );
                ois.close( );
            }
            catch( Exception e )
            {
                // Se atrapan en este bloque todos los tipos de excepci�n
                registrarError( e );
                throw new PersistenciaException( "Error fatal: imposible restaurar el estado del programa (" + e.getMessage( ) + ")" );
            }
        }
        else
        {
            // El archivo no existe: es la primera vez que se ejecuta el programa
            discos = new ArrayList( );
        }
	*/
      }
  }
  
  def setEstado(state : Int) = estado = state;
  
  def getEstado() = estado;
  
  def terminar() : Unit = {
    // Acabar con la ejecución de los procesos creados por este proceso
    hijos foreach { h => 
      h.terminar();
    }
    
    // Verificar si es un proceso asíncrono
    if(!isSincrono) {
        var escritor: PrintWriter = new PrintWriter(new File(archivo));
    	escritor print resultado;
    	escritor close;
    }
    
    // Cambiar estado
    this setEstado TERMINATED;

    // Mandar información de fin de proceso al logger.
	logger ps "Proceso " + pid + " finalizado.\n" +
  		"Ejecutó el programa " + comando + ".";  
  }

  
  /**
   */
  def ejecutar() = {
    // Cambiar el estado del proceso
    this setEstado RUNNING;
    
    // Interpretar línea por línea.
    
    // Regresar el proceso al estado de espera
    this setEstado READY;
  }
  
  /**
   */
  override def toString() : String = {
    var resp : String = "";
    
    resp += pid + "\t(" + estado + ") " + programa; 
    
    resp;
  } 
  
  /**
   */
  def getPadre = parent;
  
  /**
   */
  def getPid = pid;
  
  def isCloseble() : Boolean = {
    if(parent == null) {
      estado == TERMINATED
    } else {
      parent isCloseble
    }
  }
}
